package de.tum.wi.som.prio.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import de.tum.wi.som.Node;
import de.tum.wi.som.Project;
import de.tum.wi.som.prio.PriorityRule;
import de.tum.wi.som.util.PrioUtil;

/**
 * Max ((t-LF(il)/d(il)*W(il) where W(il) is the percentage of the activity remaining to be done at time t also known as
 * critical ratio. Also described as the ratio of the time remaining to do something and the time it takes to do it.
 *
 * @author epollok
 *
 */
public class MaximumSchedulePressure implements PriorityRule {

    @Override
    public void prioritize(Project project) {
    	project.calcProjectGraph();
        Node[] nodes = project.getNodes();

        //Max ((t-LF(il)/d(il)*W(il)
        double t = project.getSink().getEarliestStart();
        double w = 1;
        double schedulePressure;
        double maxSchedulePressure;
        List<Node> remainingNodes = new ArrayList<Node>();
        remainingNodes.addAll(Arrays.asList(project.getNodes()));
        List<Node> scheduledNodes = new ArrayList<Node>();
        List<Node> accessibleNodes;
        Node nodeWithMaximumSchedulePressure = new Node(0, new int[0]);
    
        while (!remainingNodes.isEmpty()){
        	accessibleNodes = PrioUtil.determineAccesibleNodes(scheduledNodes, project.getSource(), remainingNodes);
            if (accessibleNodes.size() == 0) {
            	System.err.println("No accessible nodes found in MaximumSchedulePressure");
            	return;
            }
        	
        	schedulePressure = Double.NEGATIVE_INFINITY;
        	maxSchedulePressure = Double.NEGATIVE_INFINITY;
        	for(Node currentNode : accessibleNodes){
        		schedulePressure = (t - currentNode.getLatestFinish()) / (currentNode.getD() * w);
        		if (schedulePressure > maxSchedulePressure){
        			maxSchedulePressure = schedulePressure;
        			nodeWithMaximumSchedulePressure = currentNode;
        		}
        	}
        	scheduledNodes.add(nodeWithMaximumSchedulePressure);
        	remainingNodes.remove(nodeWithMaximumSchedulePressure);
        	t -= nodeWithMaximumSchedulePressure.getD();
        	w = scheduledNodes.size() / (double) nodes.length;
        }
        project.setNodes(scheduledNodes.toArray(new Node[scheduledNodes.size()]));
    }
    
    @Override
	public String toString(){
		return "MaximumSchedulePressure";
	}

}
